/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 metatile_map.h

	$Header: /heroes4/metatile_map.h $

	$NoKeywords: $

 ************************************************************************/

#if !defined( METATILE_MAP_H_INCLUDED )
#define METATTILE_MAP_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <algorithm>
#include <cassert>
#include <vector>

#include "map_point.h"
#include "owned_ptr.h"
#include "terrain.h"

// --------------------------------------------------------------------------
// t_metatile_map class
// --------------------------------------------------------------------------

class t_metatile_map
{
public:
	// Types
	class t_abstract_tile_map;
	class t_metatile_info;
	class t_tile_info;

	// Constructor/Destructor
	t_metatile_map( t_abstract_tile_map const & tile_map, long random_seed );
	t_metatile_map( t_metatile_map const & other );
	virtual ~t_metatile_map();

	// Member functions
	t_metatile_info const &	get_metatile_info( t_level_map_point_2d const & metatile_point ) const;
	t_tile_info const &		get_tile_info( t_level_map_point_2d const & tile_point ) const;

	// Operator
	t_metatile_map & operator=( t_metatile_map const & other );

private:
	// Types
	class t_impl;

	// Data members
	t_owned_ptr< t_impl >	m_impl_ptr;
};

// --------------------------------------------------------------------------
// t_metatile_map::t_abstract_tile_map class
// --------------------------------------------------------------------------

class t_metatile_map::t_abstract_tile_map
{
public:
	// Member functions
	virtual void get_size( int & size, int & num_levels ) const = 0;
	virtual void get_row_bounds( int row, int & start, int & end ) const = 0;

protected:
	// Destructor
	~t_abstract_tile_map();
};

inline t_metatile_map::t_abstract_tile_map::~t_abstract_tile_map()
{
}

// --------------------------------------------------------------------------
// t_metatile_map::t_metatile_info class
// --------------------------------------------------------------------------

class t_metatile_map::t_metatile_info
{
public:
	// Member functions
	int						get_texture_num( t_road_type road_type ) const;
	int						get_texture_num( t_terrain_type terrain, int terrain_subtype ) const;
	t_map_point_2d const &	get_offset() const;
	void					set_texture_num( t_road_type road_type, int new_texture_num );
	void					set_texture_num( t_terrain_type terrain, int terrain_subtype, int new_texture_num );
	void					set_offset( t_map_point_2d const & new_offset );	

private:
	// Data members
	int				m_road_texture_num_array[ k_road_type_count - 1 ];
	int				m_terrain_texture_num_array[ k_terrain_count ][ k_terrain_subtype_max ];
	t_map_point_2d	m_offset;
};

// --------------------------------------------------------------------------
// t_metatile_map::t_metatile_info inline members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline int t_metatile_map::t_metatile_info::get_texture_num( t_road_type road_type ) const
{
	assert( road_type >= 0 && road_type < k_road_type_count );
	assert( road_type != k_road_none );
	return m_road_texture_num_array[ road_type - 1 ];
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline int t_metatile_map::t_metatile_info::get_texture_num( t_terrain_type terrain, int terrain_subtype ) const
{
	assert( terrain >= 0 && terrain < k_terrain_count );
	assert( terrain_subtype >= 0 && terrain_subtype < get_terrain_subtype_count( terrain ) );
	return m_terrain_texture_num_array[ terrain ][ terrain_subtype ];
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline t_map_point_2d const & t_metatile_map::t_metatile_info::get_offset() const
{
	return m_offset;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline void t_metatile_map::t_metatile_info::set_texture_num( t_road_type road_type, int new_texture_num )
{
	assert( road_type >= 0 && road_type < k_road_type_count );
	assert( road_type != k_road_none );
	m_road_texture_num_array[ road_type - 1 ] = new_texture_num;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline void t_metatile_map::t_metatile_info::set_texture_num( t_terrain_type terrain, int terrain_subtype, int new_texture_num )
{
	assert( terrain >= 0 && terrain < k_terrain_count );
	assert( terrain_subtype >= 0 && terrain_subtype < get_terrain_subtype_count( terrain ) );
	m_terrain_texture_num_array[ terrain ][ terrain_subtype ] = new_texture_num;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline void t_metatile_map::t_metatile_info::set_offset( t_map_point_2d const & new_offset )
{
	m_offset = new_offset;
}

// --------------------------------------------------------------------------
// t_metatile_map::t_tile_info class
// --------------------------------------------------------------------------

class t_metatile_map::t_tile_info
{
public:
	// Constructor
	t_tile_info();
	t_tile_info( t_tile_info const & other );

	// Member functions
	int				get_intersecting_metatile_count() const;
	t_map_point_2d	get_intersecting_metatile_point( int metatile_num ) const;
	void			set_intersecting_metatile_points(
						std::vector< t_map_point_2d > const &	new_metatile_point_vector );

	// Operator
	t_tile_info &	operator=( t_tile_info const & other );

private:
	// Types
	struct t_point
	{
		unsigned char	row;
		unsigned char	col;
	};

	// Data members
	t_owned_array< t_point >	m_metatile_points;
	int							m_metatile_point_count;
};

// --------------------------------------------------------------------------
// t_metatile_map::t_tile_info inline members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline t_metatile_map::t_tile_info::t_tile_info()
	:	m_metatile_point_count( 0 )
{
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline int
t_metatile_map::t_tile_info::get_intersecting_metatile_count() const
{
	return m_metatile_point_count;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline t_map_point_2d
t_metatile_map::t_tile_info::get_intersecting_metatile_point(
	int	metatile_num ) const
{
	assert( metatile_num >= 0 && metatile_num < m_metatile_point_count );
	t_point const & point = m_metatile_points[ metatile_num ];
	return t_map_point_2d( point.row, point.col );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline t_metatile_map::t_tile_info &
t_metatile_map::t_tile_info::operator=( t_tile_info const & other )
{
	t_tile_info copy( other );
	m_metatile_points.swap( copy.m_metatile_points );
	std::swap( m_metatile_point_count, copy.m_metatile_point_count );
	return *this;
}

#endif // !defined( METATILE_MAP_H_INCLUDED )
